<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.9.0">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    
    <title>
        Java 面试题系列篇-Hibernate 框架 |
        
        Darklovy</title>
    <meta name="description" content>
    <meta name="keywords" content>
    <meta name="HandheldFriendly" content="True">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="shortcut icon" href="/">
    <link rel="alternate" href="/atom.xml" title="Darklovy">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="description" content="Hibernate 框架什么是ORM？答：对象关系映射（Object-Relational Mapping，简称ORM）是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术；简单的说，ORM是通过使用描述对象和数据库之间映射的元数据（在Java中可以用XML或者是注解），将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成Java对象，其本质上就是将数据从一种形式转">
<meta name="keywords" content="Java">
<meta property="og:type" content="article">
<meta property="og:title" content="Java 面试题系列篇-Hibernate 框架">
<meta property="og:url" content="https://www.ttxxly.top/2018/10/20/Java-面试题系列篇-Hibernate-框架/index.html">
<meta property="og:site_name" content="Darklovy">
<meta property="og:description" content="Hibernate 框架什么是ORM？答：对象关系映射（Object-Relational Mapping，简称ORM）是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术；简单的说，ORM是通过使用描述对象和数据库之间映射的元数据（在Java中可以用XML或者是注解），将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成Java对象，其本质上就是将数据从一种形式转">
<meta property="og:locale" content="en">
<meta property="og:updated_time" content="2018-12-25T07:27:58.295Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java 面试题系列篇-Hibernate 框架">
<meta name="twitter:description" content="Hibernate 框架什么是ORM？答：对象关系映射（Object-Relational Mapping，简称ORM）是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术；简单的说，ORM是通过使用描述对象和数据库之间映射的元数据（在Java中可以用XML或者是注解），将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成Java对象，其本质上就是将数据从一种形式转">

    <link href="https://fonts.googleapis.com/css?family=Inconsolata|Titillium+Web" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
    <link href="//cdn.bootcss.com/node-waves/0.7.5/waves.min.css" rel="stylesheet">
    <link rel="stylesheet" href="/style.css">
    <script>
        function setLoadingBarProgress(num) {
            document.getElementById('loading-bar').style.width = num + "%";
        }
    </script>
</head>
</html>
<body>
  <div id="loading-bar-wrapper">
  <div id="loading-bar"></div>
</div>


  <script>setLoadingBarProgress(20)</script> 
  <header class="l_header">
	<div class='wrapper'>
		<div class="nav-main container container--flex">
			<a class="logo flat-box" href='/' >
				Darklovy
			</a>
			<div class='menu'>
				<ul class='h-list'>
					
						<li>
							<a class='flat-box nav-Home' href='/'>
								首页
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-archives' href='/archives'>
								归档
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-categories' href='/categories'>
								分类
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-tags' href='/tags'>
								标签
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-algorithm' href='https://book.algorithm.ttxxly.top/'>
								算法
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-python' href='https://book.python.ttxxly.top/'>
								python
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-about' href='/about'>
								关于
							</a>
						</li>
					
				</ul>
				<div class='underline'></div>
			</div>
			
				<div class="m_search">
					<form name="searchform" class="form u-search-form">
						<input type="text" class="input u-search-input" placeholder="Search" />
						<span class="icon icon-search"></span>
					</form>
				</div>
			
			<ul class='switcher h-list'>
				
					<li class='s-search'><a href='javascript:void(0)'><span class="icon icon-search flat-box"></span></a></li>
				
				<li class='s-menu'><a href='javascript:void(0)'><span class="icon icon-menu flat-box"></span></a></li>
			</ul>
		</div>
		
		<div class='nav-sub container container--flex'>
			<a class="logo" class="flat-box" href='javascript:void(0)'>
				Word of Forks
			</a>

			<ul class='switcher h-list'>
				<li class='s-comment'><a href='javascript:void(0)'><span class="icon icon-chat_bubble_outline flat-box"></span></a></li>
				<li class='s-top'><a href='javascript:void(0)'><span class="icon icon-arrow_upward flat-box"></span></a></li>
				<li class='s-toc'><a href='javascript:void(0)'><span class="icon icon-format_list_numbered flat-box"></span></a></li>
			</ul>
		</div>
	</div>
</header>
<aside class="menu-phone">
	<nav>
		
			<a href="/" class="nav-Home nav">
				首页
			</a>
		
			<a href="/archives" class="nav-archives nav">
				归档
			</a>
		
			<a href="/categories" class="nav-categories nav">
				分类
			</a>
		
			<a href="/tags" class="nav-tags nav">
				标签
			</a>
		
			<a href="https://book.algorithm.ttxxly.top/" class="nav-algorithm nav">
				算法
			</a>
		
			<a href="https://book.python.ttxxly.top/" class="nav-python nav">
				python
			</a>
		
			<a href="/about" class="nav-about nav">
				关于
			</a>
		
	</nav>
</aside>

    <script>setLoadingBarProgress(40);</script>
  <div class="l_body">
    <div class='container clearfix'>
      <div class='l_main'>
        <article id="post-Java-面试题系列篇-Hibernate-框架"
  class="post white-box article-type-post"
  itemscope itemprop="blogPost">
	<section class='meta'>
	<h2 class="title">
  	<a href="/2018/10/20/Java-面试题系列篇-Hibernate-框架/">
    	Java 面试题系列篇-Hibernate 框架
    </a>
  </h2>
	<time>
	  Oct 20, 2018
	</time>
	
	</section>
	
		<section class="toc-wrapper"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Hibernate-框架"><span class="toc-number">1.</span> <span class="toc-text">Hibernate 框架</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#什么是ORM？"><span class="toc-number">1.1.</span> <span class="toc-text">什么是ORM？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#持久层设计要考虑的问题有哪些？你用过的持久层框架有哪些？"><span class="toc-number">1.2.</span> <span class="toc-text">持久层设计要考虑的问题有哪些？你用过的持久层框架有哪些？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate中SessionFactory是线程安全的吗？Session是线程安全的吗（两个线程能够共享同一个Session吗）？"><span class="toc-number">1.3.</span> <span class="toc-text">Hibernate中SessionFactory是线程安全的吗？Session是线程安全的吗（两个线程能够共享同一个Session吗）？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate中Session的load和get方法的区别是什么？"><span class="toc-number">1.4.</span> <span class="toc-text">Hibernate中Session的load和get方法的区别是什么？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Session的save-、update-、merge-、lock-、saveOrUpdate-和persist-方法分别是做什么的？有什么区别？"><span class="toc-number">1.5.</span> <span class="toc-text">Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分别是做什么的？有什么区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#阐述Session加载实体对象的过程。"><span class="toc-number">1.6.</span> <span class="toc-text">阐述Session加载实体对象的过程。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Query接口的list方法和iterate方法有什么区别？"><span class="toc-number">1.7.</span> <span class="toc-text">Query接口的list方法和iterate方法有什么区别？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate如何实现分页查询？"><span class="toc-number">1.8.</span> <span class="toc-text">Hibernate如何实现分页查询？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#锁机制有什么用？简述Hibernate的悲观锁和乐观锁机制。"><span class="toc-number">1.9.</span> <span class="toc-text">锁机制有什么用？简述Hibernate的悲观锁和乐观锁机制。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#阐述实体对象的三种状态以及转换关系。"><span class="toc-number">1.10.</span> <span class="toc-text">阐述实体对象的三种状态以及转换关系。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#如何理解Hibernate的延迟加载机制？在实际应用中，延迟加载与Session关闭的矛盾是如何处理的？"><span class="toc-number">1.11.</span> <span class="toc-text">如何理解Hibernate的延迟加载机制？在实际应用中，延迟加载与Session关闭的矛盾是如何处理的？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#举一个多对多关联的例子，并说明如何实现多对多关联映射。"><span class="toc-number">1.12.</span> <span class="toc-text">举一个多对多关联的例子，并说明如何实现多对多关联映射。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#谈一下你对继承映射的理解。"><span class="toc-number">1.13.</span> <span class="toc-text">谈一下你对继承映射的理解。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#简述Hibernate常见优化策略。"><span class="toc-number">1.14.</span> <span class="toc-text">简述Hibernate常见优化策略。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#谈一谈Hibernate的一级缓存、二级缓存和查询缓存。"><span class="toc-number">1.15.</span> <span class="toc-text">谈一谈Hibernate的一级缓存、二级缓存和查询缓存。</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate中DetachedCriteria类是做什么的？"><span class="toc-number">1.16.</span> <span class="toc-text">Hibernate中DetachedCriteria类是做什么的？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#OneToMany注解的mappedBy属性有什么作用？"><span class="toc-number">1.17.</span> <span class="toc-text">@OneToMany注解的mappedBy属性有什么作用？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Hibernate-的缓存原理是什么？延迟加载原理是什么？"><span class="toc-number">1.18.</span> <span class="toc-text">Hibernate 的缓存原理是什么？延迟加载原理是什么？</span></a></li></ol></li></ol></section>
	
	<section class="article typo">
  	<div class="article-entry" itemprop="articleBody">
    	<h2 id="Hibernate-框架"><a href="#Hibernate-框架" class="headerlink" title="Hibernate 框架"></a>Hibernate 框架</h2><h3 id="什么是ORM？"><a href="#什么是ORM？" class="headerlink" title="什么是ORM？"></a>什么是ORM？</h3><p>答：对象关系映射（Object-Relational Mapping，简称ORM）是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术；简单的说，ORM是通过使用描述对象和数据库之间映射的元数据（在Java中可以用XML或者是注解），将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成Java对象，其本质上就是将数据从一种形式转换到另外一种形式。</p>
<h3 id="持久层设计要考虑的问题有哪些？你用过的持久层框架有哪些？"><a href="#持久层设计要考虑的问题有哪些？你用过的持久层框架有哪些？" class="headerlink" title="持久层设计要考虑的问题有哪些？你用过的持久层框架有哪些？"></a>持久层设计要考虑的问题有哪些？你用过的持久层框架有哪些？</h3><p> 答：所谓”持久”就是将数据保存到可掉电式存储设备中以便今后使用，简单的说，就是将内存中的数据保存到关系型数据库、文件系统、消息队列等提供持久化支持的设备中。持久层就是系统中专注于实现数据持久化的相对独立的层面。</p>
<p>持久层设计的目标包括： </p>
<ul>
<li>数据存储逻辑的分离，提供抽象化的数据访问接口。 </li>
<li>数据访问底层实现的分离，可以在不修改代码的情况下切换底层实现。 </li>
<li>资源管理和调度的分离，在数据访问层实现统一的资源调度（如缓存机制）。 </li>
<li>数据抽象，提供更面向对象的数据操作。</li>
</ul>
<p>持久层框架有： </p>
<ul>
<li>Hibernate </li>
<li>MyBatis </li>
<li>TopLink </li>
<li>Guzz </li>
<li>jOOQ </li>
<li>Spring Data </li>
<li>ActiveJDBC</li>
</ul>
<h3 id="Hibernate中SessionFactory是线程安全的吗？Session是线程安全的吗（两个线程能够共享同一个Session吗）？"><a href="#Hibernate中SessionFactory是线程安全的吗？Session是线程安全的吗（两个线程能够共享同一个Session吗）？" class="headerlink" title="Hibernate中SessionFactory是线程安全的吗？Session是线程安全的吗（两个线程能够共享同一个Session吗）？"></a>Hibernate中SessionFactory是线程安全的吗？Session是线程安全的吗（两个线程能够共享同一个Session吗）？</h3><p> 答：SessionFactory对应Hibernate的一个数据存储的概念，它是线程安全的，可以被多个线程并发访问。SessionFactory一般只会在启动的时候构建。对于应用程序，最好将SessionFactory通过单例模式进行封装以便于访问。Session是一个轻量级非线程安全的对象（线程间不能共享session），它表示与数据库进行交互的一个工作单元。Session是由SessionFactory创建的，在任务完成之后它会被关闭。Session是持久层服务对外提供的主要接口。Session会延迟获取数据库连接（也就是在需要的时候才会获取）。为了避免创建太多的session，可以使用ThreadLocal将session和当前线程绑定在一起，这样可以让同一个线程获得的总是同一个session。Hibernate 3中SessionFactory的getCurrentSession()方法就可以做到。</p>
<h3 id="Hibernate中Session的load和get方法的区别是什么？"><a href="#Hibernate中Session的load和get方法的区别是什么？" class="headerlink" title="Hibernate中Session的load和get方法的区别是什么？"></a>Hibernate中Session的load和get方法的区别是什么？</h3><p>答：主要有以下三项区别：<br>① 如果没有找到符合条件的记录，get方法返回null，load方法抛出异常。<br>② get方法直接返回实体类对象，load方法返回实体类对象的代理。<br>③ 在Hibernate 3之前，get方法只在一级缓存中进行数据查找，如果没有找到对应的数据则越过二级缓存，直接发出SQL语句完成数据读取；load方法则可以从二级缓存中获取数据；从Hibernate 3开始，get方法不再是对二级缓存只写不读，它也是可以访问二级缓存的。</p>
<p>说明：对于load()方法Hibernate认为该数据在数据库中一定存在可以放心的使用代理来实现延迟加载，如果没有数据就抛出异常，而通过get()方法获取的数据可以不存在。</p>
<h3 id="Session的save-、update-、merge-、lock-、saveOrUpdate-和persist-方法分别是做什么的？有什么区别？"><a href="#Session的save-、update-、merge-、lock-、saveOrUpdate-和persist-方法分别是做什么的？有什么区别？" class="headerlink" title="Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分别是做什么的？有什么区别？"></a>Session的save()、update()、merge()、lock()、saveOrUpdate()和persist()方法分别是做什么的？有什么区别？</h3><p> 答：Hibernate的对象有三种状态：瞬时态（transient）、持久态（persistent）和游离态（detached），如第135题中的图所示。瞬时态的实例可以通过调用save()、persist()或者saveOrUpdate()方法变成持久态；游离态的实例可以通过调用 update()、saveOrUpdate()、lock()或者replicate()变成持久态。save()和persist()将会引发SQL的INSERT语句，而update()或merge()会引发UPDATE语句。save()和update()的区别在于一个是将瞬时态对象变成持久态，一个是将游离态对象变为持久态。merge()方法可以完成save()和update()方法的功能，它的意图是将新的状态合并到已有的持久化对象上或创建新的持久化对象。对于persist()方法，按照官方文档的说明：① persist()方法把一个瞬时态的实例持久化，但是并不保证标识符被立刻填入到持久化实例中，标识符的填入可能被推迟到flush的时间；② persist()方法保证当它在一个事务外部被调用的时候并不触发一个INSERT语句，当需要封装一个长会话流程的时候，persist()方法是很有必要的；③ save()方法不保证第②条，它要返回标识符，所以它会立即执行INSERT语句，不管是在事务内部还是外部。至于lock()方法和update()方法的区别，update()方法是把一个已经更改过的脱管状态的对象变成持久状态；lock()方法是把一个没有更改过的脱管状态的对象变成持久状态。</p>
<h3 id="阐述Session加载实体对象的过程。"><a href="#阐述Session加载实体对象的过程。" class="headerlink" title="阐述Session加载实体对象的过程。"></a>阐述Session加载实体对象的过程。</h3><p>答：Session加载实体对象的步骤是：<br>① Session在调用数据库查询功能之前，首先会在一级缓存中通过实体类型和主键进行查找，如果一级缓存查找命中且数据状态合法，则直接返回；<br>② 如果一级缓存没有命中，接下来Session会在当前NonExists记录（相当于一个查询黑名单，如果出现重复的无效查询可以迅速做出判断，从而提升性能）中进行查找，如果NonExists中存在同样的查询条件，则返回null；<br>③ 如果一级缓存查询失败则查询二级缓存，如果二级缓存命中则直接返回；<br>④ 如果之前的查询都未命中，则发出SQL语句，如果查询未发现对应记录则将此次查询添加到Session的NonExists中加以记录，并返回null；<br>⑤ 根据映射配置和SQL语句得到ResultSet，并创建对应的实体对象；<br>⑥ 将对象纳入Session（一级缓存）的管理；<br>⑦ 如果有对应的拦截器，则执行拦截器的onLoad方法；<br>⑧ 如果开启并设置了要使用二级缓存，则将数据对象纳入二级缓存；<br>⑨ 返回数据对象。</p>
<h3 id="Query接口的list方法和iterate方法有什么区别？"><a href="#Query接口的list方法和iterate方法有什么区别？" class="headerlink" title="Query接口的list方法和iterate方法有什么区别？"></a>Query接口的list方法和iterate方法有什么区别？</h3><p> 答：<br>① list()方法无法利用一级缓存和二级缓存（对缓存只写不读），它只能在开启查询缓存的前提下使用查询缓存；iterate()方法可以充分利用缓存，如果目标数据只读或者读取频繁，使用iterate()方法可以减少性能开销。<br>② list()方法不会引起N+1查询问题，而iterate()方法可能引起N+1查询问题</p>
<p>说明：关于N+1查询问题，可以参考CSDN上的一篇文章《什么是N+1查询》</p>
<h3 id="Hibernate如何实现分页查询？"><a href="#Hibernate如何实现分页查询？" class="headerlink" title="Hibernate如何实现分页查询？"></a>Hibernate如何实现分页查询？</h3><p>答：通过Hibernate实现分页查询，开发人员只需要提供HQL语句（调用Session的createQuery()方法）或查询条件（调用Session的createCriteria()方法）、设置查询起始行数（调用Query或Criteria接口的setFirstResult()方法）和最大查询行数（调用Query或Criteria接口的setMaxResults()方法），并调用Query或Criteria接口的list()方法，Hibernate会自动生成分页查询的SQL语句。</p>
<h3 id="锁机制有什么用？简述Hibernate的悲观锁和乐观锁机制。"><a href="#锁机制有什么用？简述Hibernate的悲观锁和乐观锁机制。" class="headerlink" title="锁机制有什么用？简述Hibernate的悲观锁和乐观锁机制。"></a>锁机制有什么用？简述Hibernate的悲观锁和乐观锁机制。</h3><p>答：有些业务逻辑在执行过程中要求对数据进行排他性的访问，于是需要通过一些机制保证在此过程中数据被锁住不会被外界修改，这就是所谓的锁机制。<br>Hibernate支持悲观锁和乐观锁两种锁机制。悲观锁，顾名思义悲观的认为在数据处理过程中极有可能存在修改数据的并发事务（包括本系统的其他事务或来自外部系统的事务），于是将处理的数据设置为锁定状态。悲观锁必须依赖数据库本身的锁机制才能真正保证数据访问的排他性，关于数据库的锁机制和事务隔离级别在《Java面试题大全（上）》中已经讨论过了。乐观锁，顾名思义，对并发事务持乐观态度（认为对数据的并发操作不会经常性的发生），通过更加宽松的锁机制来解决由于悲观锁排他性的数据访问对系统性能造成的严重影响。最常见的乐观锁是通过数据版本标识来实现的，读取数据时获得数据的版本号，更新数据时将此版本号加1，然后和数据库表对应记录的当前版本号进行比较，如果提交的数据版本号大于数据库中此记录的当前版本号则更新数据，否则认为是过期数据无法更新。Hibernate中通过Session的get()和load()方法从数据库中加载对象时可以通过参数指定使用悲观锁；而乐观锁可以通过给实体类加整型的版本字段再通过XML或@Version注解进行配置。</p>
<p>提示：使用乐观锁会增加了一个版本字段，很明显这需要额外的空间来存储这个版本字段，浪费了空间，但是乐观锁会让系统具有更好的并发性，这是对时间的节省。因此乐观锁也是典型的空间换时间的策略。</p>
<h3 id="阐述实体对象的三种状态以及转换关系。"><a href="#阐述实体对象的三种状态以及转换关系。" class="headerlink" title="阐述实体对象的三种状态以及转换关系。"></a>阐述实体对象的三种状态以及转换关系。</h3><p> 答：最新的Hibernate文档中为Hibernate对象定义了四种状态（原来是三种状态，面试的时候基本上问的也是三种状态），分别是：瞬时态（new, or transient）、持久态（managed, or persistent）、游状态（detached）和移除态（removed，以前Hibernate文档中定义的三种状态中没有移除态），如下图所示，就以前的Hibernate文档中移除态被视为是瞬时态。</p>
<p>瞬时态：当new一个实体对象后，这个对象处于瞬时态，即这个对象只是一个保存临时数据的内存区域，如果没有变量引用这个对象，则会被JVM的垃圾回收机制回收。这个对象所保存的数据与数据库没有任何关系，除非通过Session的save()、saveOrUpdate()、persist()、merge()方法把瞬时态对象与数据库关联，并把数据插入或者更新到数据库，这个对象才转换为持久态对象。</p>
<p>持久态：持久态对象的实例在数据库中有对应的记录，并拥有一个持久化标识（ID）。对持久态对象进行delete操作后，数据库中对应的记录将被删除，那么持久态对象与数据库记录不再存在对应关系，持久态对象变成移除态（可以视为瞬时态）。持久态对象被修改变更后，不会马上同步到数据库，直到数据库事务提交。</p>
<p>游离态：当Session进行了close()、clear()、evict()或flush()后，实体对象从持久态变成游离态，对象虽然拥有持久和与数据库对应记录一致的标识值，但是因为对象已经从会话中清除掉，对象不在持久化管理之内，所以处于游离态（也叫脱管态）。游离态的对象与临时状态对象是十分相似的，只是它还含有持久化标识。</p>
<p>提示：关于这个问题，在Hibernate的官方文档中有更为详细的解读。</p>
<h3 id="如何理解Hibernate的延迟加载机制？在实际应用中，延迟加载与Session关闭的矛盾是如何处理的？"><a href="#如何理解Hibernate的延迟加载机制？在实际应用中，延迟加载与Session关闭的矛盾是如何处理的？" class="headerlink" title="如何理解Hibernate的延迟加载机制？在实际应用中，延迟加载与Session关闭的矛盾是如何处理的？"></a>如何理解Hibernate的延迟加载机制？在实际应用中，延迟加载与Session关闭的矛盾是如何处理的？</h3><p>答：延迟加载就是并不是在读取的时候就把数据加载进来，而是等到使用时再加载。Hibernate使用了虚拟代理机制实现延迟加载，我们使用Session的load()方法加载数据或者一对多关联映射在使用延迟加载的情况下从一的一方加载多的一方，得到的都是虚拟代理，简单的说返回给用户的并不是实体本身，而是实体对象的代理。代理对象在用户调用getter方法时才会去数据库加载数据。但加载数据就需要数据库连接。而当我们把会话关闭时，数据库连接就同时关闭了。</p>
<p>延迟加载与session关闭的矛盾一般可以这样处理：<br>① 关闭延迟加载特性。这种方式操作起来比较简单，因为Hibernate的延迟加载特性是可以通过映射文件或者注解进行配置的，但这种解决方案存在明显的缺陷。首先，出现”no session or session was closed”通常说明系统中已经存在主外键关联，如果去掉延迟加载的话，每次查询的开销都会变得很大。<br>② 在session关闭之前先获取需要查询的数据，可以使用工具方法Hibernate.isInitialized()判断对象是否被加载，如果没有被加载则可以使用Hibernate.initialize()方法加载对象。<br>③ 使用拦截器或过滤器延长Session的生命周期直到视图获得数据。Spring整合Hibernate提供的OpenSessionInViewFilter和OpenSessionInViewInterceptor就是这种做法。</p>
<h3 id="举一个多对多关联的例子，并说明如何实现多对多关联映射。"><a href="#举一个多对多关联的例子，并说明如何实现多对多关联映射。" class="headerlink" title="举一个多对多关联的例子，并说明如何实现多对多关联映射。"></a>举一个多对多关联的例子，并说明如何实现多对多关联映射。</h3><p> 答：例如：商品和订单、学生和课程都是典型的多对多关系。可以在实体类上通过@ManyToMany注解配置多对多关联或者通过映射文件中的和标签配置多对多关联，但是实际项目开发中，很多时候都是将多对多关联映射转换成两个多对一关联映射来实现的。</p>
<h3 id="谈一下你对继承映射的理解。"><a href="#谈一下你对继承映射的理解。" class="headerlink" title="谈一下你对继承映射的理解。"></a>谈一下你对继承映射的理解。</h3><p> 答：继承关系的映射策略有三种：<br>① 每个继承结构一张表（table per class hierarchy），不管多少个子类都用一张表。<br>② 每个子类一张表（table per subclass），公共信息放一张表，特有信息放单独的表。<br>③ 每个具体类一张表（table per concrete class），有多少个子类就有多少张表。<br>第一种方式属于单表策略，其优点在于查询子类对象的时候无需表连接，查询速度快，适合多态查询；缺点是可能导致表很大。后两种方式属于多表策略，其优点在于数据存储紧凑，其缺点是需要进行连接查询，不适合多态查询。</p>
<h3 id="简述Hibernate常见优化策略。"><a href="#简述Hibernate常见优化策略。" class="headerlink" title="简述Hibernate常见优化策略。"></a>简述Hibernate常见优化策略。</h3><p> 答：这个问题应当挑自己使用过的优化策略回答，常用的有：<br>① 制定合理的缓存策略（二级缓存、查询缓存）。<br>② 采用合理的Session管理机制。<br>③ 尽量使用延迟加载特性。<br>④ 设定合理的批处理参数。<br>⑤ 如果可以，选用UUID作为主键生成器。<br>⑥ 如果可以，选用基于版本号的乐观锁替代悲观锁。<br>⑦ 在开发过程中, 开启hibernate.show_sql选项查看生成的SQL，从而了解底层的状况；开发完成后关闭此选项。<br>⑧ 考虑数据库本身的优化，合理的索引、恰当的数据分区策略等都会对持久层的性能带来可观的提升，但这些需要专业的DBA（数据库管理员）提供支持。</p>
<h3 id="谈一谈Hibernate的一级缓存、二级缓存和查询缓存。"><a href="#谈一谈Hibernate的一级缓存、二级缓存和查询缓存。" class="headerlink" title="谈一谈Hibernate的一级缓存、二级缓存和查询缓存。"></a>谈一谈Hibernate的一级缓存、二级缓存和查询缓存。</h3><p>答：Hibernate的Session提供了一级缓存的功能，默认总是有效的，当应用程序保存持久化实体、修改持久化实体时，Session并不会立即把这种改变提交到数据库，而是缓存在当前的Session中，除非显示调用了Session的flush()方法或通过close()方法关闭Session。通过一级缓存，可以减少程序与数据库的交互，从而提高数据库访问性能。<br>SessionFactory级别的二级缓存是全局性的，所有的Session可以共享这个二级缓存。不过二级缓存默认是关闭的，需要显示开启并指定需要使用哪种二级缓存实现类（可以使用第三方提供的实现）。一旦开启了二级缓存并设置了需要使用二级缓存的实体类，SessionFactory就会缓存访问过的该实体类的每个对象，除非缓存的数据超出了指定的缓存空间。<br>一级缓存和二级缓存都是对整个实体进行缓存，不会缓存普通属性，如果希望对普通属性进行缓存，可以使用查询缓存。查询缓存是将HQL或SQL语句以及它们的查询结果作为键值对进行缓存，对于同样的查询可以直接从缓存中获取数据。查询缓存默认也是关闭的，需要显示开启。</p>
<h3 id="Hibernate中DetachedCriteria类是做什么的？"><a href="#Hibernate中DetachedCriteria类是做什么的？" class="headerlink" title="Hibernate中DetachedCriteria类是做什么的？"></a>Hibernate中DetachedCriteria类是做什么的？</h3><p>答：DetachedCriteria和Criteria的用法基本上是一致的，但Criteria是由Session的createCriteria()方法创建的，也就意味着离开创建它的Session，Criteria就无法使用了。DetachedCriteria不需要Session就可以创建（使用DetachedCriteria.forClass()方法创建），所以通常也称其为离线的Criteria，在需要进行查询操作的时候再和Session绑定（调用其getExecutableCriteria(Session)方法），这也就意味着一个DetachedCriteria可以在需要的时候和不同的Session进行绑定。</p>
<h3 id="OneToMany注解的mappedBy属性有什么作用？"><a href="#OneToMany注解的mappedBy属性有什么作用？" class="headerlink" title="@OneToMany注解的mappedBy属性有什么作用？"></a>@OneToMany注解的mappedBy属性有什么作用？</h3><p>答：@OneToMany用来配置一对多关联映射，但通常情况下，一对多关联映射都由多的一方来维护关联关系，例如学生和班级，应该在学生类中添加班级属性来维持学生和班级的关联关系（在数据库中是由学生表中的外键班级编号来维护学生表和班级表的多对一关系），如果要使用双向关联，在班级类中添加一个容器属性来存放学生，并使用@OneToMany注解进行映射，此时mappedBy属性就非常重要。如果使用XML进行配置，可以用<set>标签的inverse=”true”设置来达到同样的效果。</set></p>
<h3 id="Hibernate-的缓存原理是什么？延迟加载原理是什么？"><a href="#Hibernate-的缓存原理是什么？延迟加载原理是什么？" class="headerlink" title="Hibernate 的缓存原理是什么？延迟加载原理是什么？"></a>Hibernate 的缓存原理是什么？延迟加载原理是什么？</h3>
  	</div>
	  
	  <div class="article-tags tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
		
	
		<div class="art-item-footer">
				
					<span class="art-item-left"><i class="icon icon-chevron-thin-left"></i>prev：<a href="/2018/10/20/Java-面试题系列篇-Mybatis-框架/" rel="prev"  title="Java 面试题系列篇-Mybatis 框架">
						Java 面试题系列篇-Mybatis 框架 
					</a></span>
				
				
					<span class="art-item-right">next：<a href="/2018/10/20/Java-面试题系列篇-概念解释/" rel="next"  title="Java 面试题系列篇-概念解释">
						Java 面试题系列篇-概念解释
					</a><i class="icon icon-chevron-thin-right"></i></span>
				
		</div>
	
	</section>
	
</article>
<script>
	window.subData = {
		title: 'Java 面试题系列篇-Hibernate 框架',
		tools: true
	}
</script>

      </div>
      <aside class='l_side'>
        
  <section class='m_widget links'>
<div class='header'>Links</div>
<div class='content'>
    <ul class="entry">
    
        <li><a class="flat-box" target="_blank" href="https://iiong.com/">
            <div class='name'>淮城一只猫</div>
        </a></li>
    
    </ul>
</div>
</section>

  <section class='m_widget categories'>
<div class='header'>Categories</div>
<div class='content'>
    
    <ul class="entry">
    
        <li><a class="flat-box" href="/categories/Android基础/"><div class='name'>Android基础</div><div class='badget'>1</div></a></li>
    
    </ul>
    
</div>
</section>

  
<div class="m_widget tagcloud">
    <div class="header">Tags</div>
    <div class='content'>
        <a href="/tags/Android/" style="font-size: 14px; color: #808080">Android</a> <a href="/tags/HTML/" style="font-size: 14px; color: #808080">HTML</a> <a href="/tags/Java/" style="font-size: 20px; color: #000">Java</a> <a href="/tags/Python/" style="font-size: 14px; color: #808080">Python</a>
    </div>
</div>



      </aside>
      <script>setLoadingBarProgress(60);</script>
    </div>
  </div>
  <footer id="footer" class="clearfix">

	<div class="social-wrapper">
  	
      
        <a href="https://github.com/stkevintan" class="social github"
          target="_blank" rel="external">
          <span class="icon icon-github"></span>
        </a>
      
        <a href="https://twitter.com/kevinsfork" class="social twitter"
          target="_blank" rel="external">
          <span class="icon icon-twitter"></span>
        </a>
      
        <a href="/atom.xml" class="social rss"
          target="_blank" rel="external">
          <span class="icon icon-rss"></span>
        </a>
      
    
  </div>
  
  <div>Theme <a href='https://github.com/stkevintan/hexo-theme-material-flow' class="codename">MaterialFlow</a> designed by <a href="http://keyin.me/" target="_blank">Kevin Tan</a>.</div>
  
</footer>


  <script>setLoadingBarProgress(80);</script>
  

<script src="//apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src='//cdn.bootcss.com/node-waves/0.7.5/waves.min.js'></script>
<script src="//cdn.bootcss.com/scrollReveal.js/3.3.2/scrollreveal.min.js"></script>
<script src="/js/jquery.fitvids.js"></script>
<script>
	var GOOGLE_CUSTOM_SEARCH_API_KEY = "";
	var GOOGLE_CUSTOM_SEARCH_ENGINE_ID = "";
	var ALGOLIA_API_KEY = "";
	var ALGOLIA_APP_ID = "";
	var ALGOLIA_INDEX_NAME = "";
  var AZURE_SERVICE_NAME = "";
  var AZURE_INDEX_NAME = "";
  var AZURE_QUERY_KEY = "";
  var BAIDU_API_ID = "";
  var SEARCH_SERVICE = "hexo";
  var ROOT = "/"||"/";
  if(!ROOT.endsWith('/'))ROOT += '/';
</script>
<script src="/js/search.js"></script>
<script src="/js/app.js"></script>


  <script>setLoadingBarProgress(100);</script>
</body>
</html>
